package com.ysc.execute;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.ysc.constant.GeneratorConstant;
import com.ysc.databaseconfig.DataSourcesConfig;
import com.ysc.util.CodeGeneratorUtils;
import org.apache.commons.lang3.StringUtils;

import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
import java.util.function.Consumer;

/**
 * @className: MyCommentGenerator
 * @description: MyBatis Plus 自动生成代码配置类
 * @author: YaoSiCheng
 * @date: 2024-07-09 08:47
 **/
public class MyCommentGenerator {


    /**
     * 表名逗号分割 "表名", "表名"
     */
    private static final String[] INCLUDE = new String[]{
            ""
    };

    public static void main(String[] args) {
        // 获取当前目录路径
        String projectPath = GeneratorConstant.PROJECT_PATH;
        if (StringUtils.isBlank(projectPath)) {
            projectPath = System.getProperty("user.dir");
        }
        // 父包名
        String parentModuleName = GeneratorConstant.PARENT_MODULE_NAME;
        if (StringUtils.isBlank(parentModuleName)) {
            parentModuleName = scanner("输入父包名类似[com.ysc.models]");
        }
        String moduleName = GeneratorConstant.MODULE_NAME;
        if (StringUtils.isBlank(moduleName)) {
            moduleName = scanner("模块名");
        }
        String[] tableNames = INCLUDE;
        if (tableNames.length == 0) {
            tableNames = scanner("表名,多个英文逗号分割").replaceAll("，", ",").split(",");
        }

        // 输出目录
        String outPath = projectPath + GeneratorConstant.OUTPUT_DIR;
        // 删除输出目录
        CodeGeneratorUtils.deleteGeneratedFiles(outPath);
        //删除xml文件
        CodeGeneratorUtils.deleteGeneratedFiles(projectPath + "/src/main/resources/mapper/");

        // 代码生成器: 数据源配置
        AutoGenerator autoGenerator = new AutoGenerator(initDataSourceConfig());

        // 全局配置
        autoGenerator.global(initGlobalConfig(outPath));

        // 包配置，如模块名、实体、mapper、service、controller等
        autoGenerator.packageInfo(initPackageConfig(projectPath, parentModuleName, moduleName));

        // 模板配置
        autoGenerator.template(initTemplateConfig());

        // 自定义配置
        autoGenerator.injection(initInjectionConfig(projectPath));

        // 策略配置
        autoGenerator.strategy(initStrategyConfig(tableNames));

        // 使用 Velocity 引擎模板，默认的是 Velocity 引擎模板
        autoGenerator.execute(new VelocityTemplateEngine());
    }

    /**
     * 读取控制台内容信息
     */
    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(("请输入" + tip + "："));
        if (scanner.hasNext()) {
            String next = scanner.next();
            if (StringUtils.isNotBlank(next)) {
                return next;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }

    /**
     * 初始化数据源配置
     */
    private static DataSourceConfig initDataSourceConfig() {
        // jdbc路径
        String url = DataSourcesConfig.getDataSource("url");
        // 数据库账号
        String username = DataSourcesConfig.getDataSource("username");
        // 数据库账号
        String password = DataSourcesConfig.getDataSource("password");
        return new DataSourceConfig
                //设置数据源
                .Builder(url, username, password)
                //设置数据库查询器
                .dbQuery(Objects.requireNonNull(DataSourcesConfig.getDbQuery()))
                // 类型转换,数据库
                .typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                    // number转换成Integer
                    if (typeCode == Types.NUMERIC) {
                        return DbColumnType.INTEGER;
                    }
                    return typeRegistry.getColumnType(metaInfo);
                }).build();
    }

    /**
     * 初始化全局配置
     */
    private static GlobalConfig initGlobalConfig(String outPath) {
        return new GlobalConfig.Builder()
                // 指定生成文件的根目录
                .outputDir(outPath)
                // 设置作者
                .author(GeneratorConstant.AUTHOR)
                // 禁止打开输出目录
                .disableOpenDir()
                // 设置时间类型
                .dateType(DateType.ONLY_DATE)
                // 注释日期
                .commentDate("yyyy-MM-dd HH:mm:ss")
                .build();
    }

    /**
     * 初始化包配置
     */
    private static PackageConfig initPackageConfig(String projectPath, String parentModuleName, String moduleName) {
        Map<OutputFile, String> pathInfo = new HashMap<>();
        pathInfo.put(OutputFile.xml, projectPath + "/src/main/resources/mapper/" + moduleName);
        return new PackageConfig.Builder()
                // 父包名
                .parent(parentModuleName)
                // 父包模块名
                .moduleName(moduleName)
                // 实体类 Entity 包名，默认值：entity
                .entity("entity")
                // Service 包名，默认值：entity
                .service("service")
                // 实现类 Service Impl 包名，默认值：service.impl
                .serviceImpl("service.impl")
                // Mapper 包名，默认值：mapper
                .mapper("mapper")
                // Mapper XML 包名，默认值：mapper.xml
                .xml("mapper.xml")
                // Controller 包名，默认值：controller
                .controller("controller")
                // 路径配置信息
                .pathInfo(pathInfo)
                .build();
    }

    /**
     * 初始化模板配置
     * 可以对 controller、service、entity 模板进行配置
     */
    private static TemplateConfig initTemplateConfig() {
        return new TemplateConfig.Builder()
                .entity("/templates/entity.java.vm")
                .service("/templates/service.java.vm")
                .serviceImpl("/templates/serviceImpl.java.vm")
                .mapper("/templates/mapper.java.vm")
                .xml("/templates/mapper.xml.vm")
                .controller("/templates/controller.java.vm")
                .build();
    }

    /**
     * 初始化自定义配置
     */
    private static InjectionConfig initInjectionConfig(String projectPath) {
        // 自定义生成模板参数
        Map<String, Object> paramMap = new HashMap<>();
        // 自定义生成类
        Map<String, String> customFileMap = new HashMap<>();

        return new InjectionConfig.Builder()
                .beforeOutputFile((tableInfo, objectMap) -> {
                    customFileMap.forEach((key, value) -> {
                        System.out.println(key + " : " + value);
                    });
                    System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
                })
                .customMap(paramMap)
                .customFile(customFileMap)
                .build();
    }

    private static Consumer<InjectionConfig.Builder> getInjectionConfigBuilder() {
        return consumer -> {
        };
    }

    /**
     * 初始化策略配置
     */
    private static StrategyConfig initStrategyConfig(String[] tableNames) {
        StrategyConfig.Builder builder = new StrategyConfig.Builder();
        // 设置表名前缀，这里指定要忽略的前缀
        builder.addTablePrefix(GeneratorConstant.IGNORE_TABLE_PREFIX);
        // 开启大写命名，默认值：false
        builder.enableCapitalMode();
        //实体类
        builder.entityBuilder()
                // 数据库表映射到实体的命名策略，默认下划线转驼峰命名：NamingStrategy.underline_to_camel
                .naming(NamingStrategy.underline_to_camel)
                // 数据库表字段映射到实体的命名策略，默认为 null，未指定按照 naming 执行
                .columnNaming(NamingStrategy.underline_to_camel)
                // 禁用生成 serialVersionUID，默认值：true
                .disableSerialVersionUID()
                // 开启链式模型，默认值：false
                .enableChainModel()
                // 开启 lombok 模型，默认值：false
                .enableLombok()
                // 开启 Boolean 类型字段移除 is 前缀，默认值：false
                .enableRemoveIsPrefix()
                // 开启生成实体时生成字段注解，默认值：false
                .enableTableFieldAnnotation()
                // 格式化文件名称
                .formatFileName("%s")
                //覆盖已有文件
                .enableFileOverride();
        //控制层
        builder.controllerBuilder()
                // 开启驼峰转连字符，默认值：false
                .enableHyphenStyle()
                // 开启生成@RestController 控制器，默认值：false
                .enableRestStyle()
                // 格式化文件名称
                .formatFileName("%sController")
                //覆盖已有文件
                .enableFileOverride();
        //服务层
        builder.serviceBuilder()
                // 格式化 service 接口文件名称
                .formatServiceFileName("I%sService")
                // 格式化 service 实现类文件名称
                .formatServiceImplFileName("%sServiceImpl")
                //覆盖已有文件
                .enableFileOverride();
        //mapper
        builder.mapperBuilder()
                // 启用 BaseResultMap 生成，默认值：false
                .enableBaseResultMap()
                // 启用 BaseColumnList，默认值：false
                .enableBaseColumnList()
                // 格式化 mapper 文件名称
                .formatMapperFileName("%sMapper")
                // 格式化 xml 实现类文件名称
                .formatXmlFileName("%sMapper")
                //覆盖已有文件
                .enableFileOverride();

        // 当表名中带*号时可以启用通配符模式
        if (tableNames.length == 1 && tableNames[0].contains("*")) {
            String[] likeStr = tableNames[0].split("_");
            String likePrefix = likeStr[0] + "_";
            builder.likeTable(new LikeTable(likePrefix));
        } else {
            builder.addInclude(tableNames);
        }
        return builder.build();
    }
}
